package service

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/zoumo/goset"
	"gorm.io/gorm"
	"guns-go/global"
	"guns-go/model"
	"guns-go/model/request"
	"guns-go/model/response"
	"guns-go/utils"
	"strconv"
	"strings"
)

func QuerySysOrgById(orgId int) (err error, sysOrg model.SysOrg) {
	var org model.SysOrg
	err = global.GVA_DB.Where("id = ?", orgId).Find(&org).Error
	return err, org
}

func SaveOrg(org *model.SysOrg, tx *gorm.DB) error {
	return tx.Create(org).Error
}

func UpdateSysOrg(org model.SysOrg, tx *gorm.DB) error {
	return tx.Model(&org).Updates(org).Error
}

func GetDataScopeListByDataScopeType(dataScopeType int8, orgId int) (err error, scopeIds []int) {

	resultSlice := make([]int, 0)

	if orgId == 0 {
		return err, resultSlice
	}

	if dataScopeType == global.ALL {
		err, resultIds := getOrgIdAll()
		if err != nil {
			return err, nil
		}
		resultSlice = resultIds
	} else if dataScopeType == global.DeptWithChild {
		err, orgIds := GetChildIdListWithSelfById(orgId)

		if err != nil {
			return err, nil
		}
		resultSlice = orgIds
	} else if dataScopeType == global.DEPT {
		resultSlice = append(resultSlice, orgId)
	}
	return err, resultSlice
}

func getOrgIdAll() (err error, results []int) {

	resultSlice := make([]int, 0)

	var orgInfos []model.SysOrg
	err = global.GVA_DB.Where("status = ?", 0).Find(&orgInfos).Error

	if err != nil {
		return err, nil
	}

	if len(orgInfos) > 0 {
		for _, orgInfo := range orgInfos {
			resultSlice = append(resultSlice, orgInfo.Id)
		}
	}
	return err, resultSlice
}

func GetChildIdListWithSelfById(id int) (err error, resultSlice []int) {

	err, childIdSlice := GetChildIdListById(id)

	if len(childIdSlice) > 0 {
		childIdSlice = append(childIdSlice, id)
		return err, childIdSlice
	} else {
		childIdSlice = make([]int, 0)
		childIdSlice = append(childIdSlice, id)
		return err, childIdSlice
	}
}

func GetChildIdListById(id int) (err error, orgIds []int) {

	childIdSlice := make([]int, 0)

	var orgInfos []model.SysOrg
	err = global.GVA_DB.Where("pids like ?", "%"+global.LeftSquareBrackets+strconv.Itoa(id)+global.RightSquareBrackets+"%").Find(&orgInfos).Error

	if err != nil {
		return err, nil
	}

	if len(orgInfos) > 0 {
		for _, orgInfo := range orgInfos {
			childIdSlice = append(childIdSlice, orgInfo.Id)
		}
	}
	return err, childIdSlice
}

func OrgInfoTree(isSuperAdmin bool, param request.SysOrgParam) (err error, antD []*response.AntdBaseTreeNode) {

	treeNodes := make([]*response.AntdBaseTreeNode, 0)

	var orgSlice []model.SysOrg
	db := global.GVA_DB

	// 如果是超级管理员则获取所有组织机构，否则只获取其数据范围的机构数据
	if !isSuperAdmin {
		dataScope := param.DataScope
		if len(dataScope) <= 0 {
			return nil, treeNodes
		} else {

			dataScopeSet := make([]int, 0)
			dataScopeSet = append(dataScopeSet, dataScope...)

			pSet := goset.NewSafeSetFromInts(dataScopeSet)
			dataScopeSet = dataScopeSet[:0]
			dataScopeSet = append(dataScopeSet, pSet.ToInts()...)

			for _, orgId := range dataScopeSet {

				//此处获取所有的上级节点，放入set，用于构造完整树
				err, parentAndChildIdListWithSelf := getParentIdListById(orgId)

				if err != nil {
					return err, nil
				}

				dataScopeSet = append(dataScopeSet, parentAndChildIdListWithSelf...)
			}

			db = db.Where("id in(?)", dataScopeSet)
		}
	}

	// 只查询未删除的
	db = db.Where("status = ?", 0)

	//根据排序升序排列，序号越小越在前
	db = db.Order("sort asc")

	err = db.Find(&orgSlice).Error

	if err != nil {
		return err, nil
	}

	for _, org := range orgSlice {
		orgTreeNode := new(response.AntdBaseTreeNode)

		orgTreeNode.Id = org.Id
		orgTreeNode.Pid = *org.Pid
		orgTreeNode.ParentId = *org.Pid
		orgTreeNode.Title = org.Name
		orgTreeNode.Value = strconv.Itoa(org.Id)
		orgTreeNode.Weight = org.Sort

		treeNodes = append(treeNodes, orgTreeNode)
	}

	return err, doTreeBuildOrg(treeNodes)
}

func getParentIdListById(id int) (err error, r []int) {
	resultSlice := make([]int, 0)

	err, sysOrg := QuerySysOrgById(id)

	if err != nil {
		return err, resultSlice
	}

	pids := sysOrg.Pids

	pidsWithRightSymbol := strings.Replace(pids, global.LeftSquareBrackets, "", -1)
	pidsNormal := strings.Replace(pidsWithRightSymbol, global.RightSquareBrackets, "", -1)

	pidsNormalArr := strings.Split(pidsNormal, global.COMMA)

	for _, pid := range pidsNormalArr {

		pidInt, err := strconv.Atoi(pid)

		if err != nil {
			return err, nil
		}
		resultSlice = append(resultSlice, pidInt)
	}
	return err, resultSlice
}

func doTreeBuildOrg(sysOrgTreeNodes []*response.AntdBaseTreeNode) (dictNodeS []*response.AntdBaseTreeNode) {

	//具体构建的过程
	buildComplete := executeBuildingOrg(sysOrgTreeNodes)

	//构建之后的处理工作
	return afterBuildOrg(buildComplete)
}

func executeBuildingOrg(sysOrgTreeNodes []*response.AntdBaseTreeNode) (dictNodeS []*response.AntdBaseTreeNode) {

	for _, node := range sysOrgTreeNodes {
		buildChildNodesOrg(sysOrgTreeNodes, node, make([]*response.AntdBaseTreeNode, 0))
	}

	return sysOrgTreeNodes
}

func buildChildNodesOrg(totalNodes []*response.AntdBaseTreeNode, node *response.AntdBaseTreeNode, childNodeSlice []*response.AntdBaseTreeNode) {

	if len(totalNodes) <= 0 || node == nil {
		return
	}

	nodeSubSlice := getSubChildLevelOneOrg(totalNodes, node)

	if len(nodeSubSlice) > 0 {
		for _, t := range nodeSubSlice {
			buildChildNodesOrg(totalNodes, t, make([]*response.AntdBaseTreeNode, 0))
		}
	}

	childNodeSlice = append(childNodeSlice, nodeSubSlice...)
	node.Children = childNodeSlice
}

func getSubChildLevelOneOrg(slice []*response.AntdBaseTreeNode, node *response.AntdBaseTreeNode) (nodeS []*response.AntdBaseTreeNode) {

	nodeSlice := make([]*response.AntdBaseTreeNode, 0)

	if len(slice) > 0 {
		for _, t := range slice {
			if t.Pid == node.Id {
				nodeSlice = append(nodeSlice, t)
			}
		}
	}
	return nodeSlice
}

func afterBuildOrg(nodes []*response.AntdBaseTreeNode) (results []*response.AntdBaseTreeNode) {

	//去掉所有的二级节点
	resultSlice := make([]*response.AntdBaseTreeNode, 0)

	for _, node := range nodes {
		if node.Pid == 0 {
			resultSlice = append(resultSlice, node)
		}
	}

	return resultSlice
}

func SysOrgList(isSuperAdmin bool, sysOrgParam *request.SysOrgParam) (err error, s []*model.SysOrg) {

	var posSlice []*model.SysOrg

	db := global.GVA_DB

	if sysOrgParam != nil {

		if sysOrgParam.Pid != nil {
			db = db.Where("pid = ?", sysOrgParam.Code)
		}

		if !isSuperAdmin {
			dataScope := sysOrgParam.DataScope
			if len(dataScope) <= 0 {
				return err, make([]*model.SysOrg, 0)
			} else {

				dataScopeSet := make([]int, 0)
				dataScopeSet = append(dataScopeSet, dataScope...)

				pSet := goset.NewSafeSetFromInts(dataScopeSet)
				dataScopeSet = dataScopeSet[:0]
				dataScopeSet = append(dataScopeSet, pSet.ToInts()...)

				for _, orgId := range dataScopeSet {

					//此处获取所有的上级节点，放入set，用于构造完整树
					err, parentAndChildIdListWithSelf := getParentIdListById(orgId)

					if err != nil {
						return err, nil
					}

					dataScopeSet = append(dataScopeSet, parentAndChildIdListWithSelf...)
				}

				db = db.Where("id in(?)", dataScopeSet)
			}
		}

		db = db.Where("status = ?", 0).Order("sort asc")

		err = db.Find(&posSlice).Error

		return err, posSlice
	}

	return err, make([]*model.SysOrg, 0)
}

func OrgPage(sysOrgParam *request.SysOrgParam, c *gin.Context) (err error, result *response.PageResult) {

	var sysOrgSlice []*model.SysOrg

	db := global.GVA_DB

	if sysOrgParam != nil {

		// 根据机构名称模糊查询
		if sysOrgParam.Name != "" {
			db = db.Where("name like ?", "%"+sysOrgParam.Name+"%")
		}

		// 根据机构id查询
		if sysOrgParam.Id != 0 {
			db = db.Where("id = ?", sysOrgParam.Id)
		}

		// 根据父机构id查询
		if sysOrgParam.Pid != nil {
			db = db.Where("id = ? or pids like ?", sysOrgParam.Pid, "%"+strconv.Itoa(*sysOrgParam.Pid)+"%")
		}

		//如果是超级管理员则获取所有用户，否则只获取其数据范围的用户
		err, superAdmin := IsSuperAdmin(c)

		if err != nil {
			return err, nil
		}

		if !superAdmin {

			dataScope := sysOrgParam.DataScope
			if len(dataScope) <= 0 {
				return nil, new(response.PageResult)
			} else {
				dataScopeSet := make([]int, 0)
				dataScopeSet = append(dataScopeSet, dataScope...)

				pSet := goset.NewSafeSetFromInts(dataScopeSet)
				dataScopeSet = dataScopeSet[:0]
				dataScopeSet = append(dataScopeSet, pSet.ToInts()...)

				for _, orgId := range dataScopeSet {

					//此处获取所有的上级节点，放入set，用于构造完整树
					err, parentAndChildIdListWithSelf := getParentIdListById(orgId)

					if err != nil {
						return err, nil
					}

					dataScopeSet = append(dataScopeSet, parentAndChildIdListWithSelf...)
				}

				db = db.Where("id in(?)", dataScopeSet)
			}
		}

		db = db.Where("status = ?", 0).Order("sort asc")

		var totalCount int64

		err = db.Find(&sysOrgSlice).Count(&totalCount).Error

		if err != nil {
			return err, nil
		}

		pageNo, pageSize, db := utils.DefaultPage(c, db)

		err = db.Find(&sysOrgSlice).Error

		if err != nil {
			return err, nil
		}

		return err, utils.CoverToPageResult(pageNo, pageSize, totalCount, sysOrgSlice)
	}
	return nil, new(response.PageResult)
}

func OrgAdd(sysOrgParam *request.SysOrgParam, c *gin.Context) error {
	//校验参数，检查是否存在相同的名称和编码
	err := checkParamByOrg(sysOrgParam, false)

	if err != nil {
		return err
	}

	//获取父id
	pid := sysOrgParam.Pid

	err, superAdmin := IsSuperAdmin(c)

	if err != nil {
		return err
	}

	if !superAdmin {
		//如果新增的机构父id不是0，则进行数据权限校验
		if *pid != 0 {
			dataScopes := sysOrgParam.DataScope

			isContain, _ := utils.Contain(pid, dataScopes)

			//数据范围为空
			if len(dataScopes) < 0 {
				return errors.New("没有权限操作该数据，请联系管理员")
			} else if !isContain {
				//所添加的组织机构的父机构不在自己的数据范围内
				return errors.New("没有权限操作该数据，请联系管理员")
			}

		} else {
			//如果新增的机构父id是0，则根本没权限，只有超级管理员能添加父id为0的节点
			return errors.New("没有权限操作该数据，请联系管理员")
		}
	}

	sysOrg := new(model.SysOrg)

	err = utils.SimpleCopyProperties(sysOrg, sysOrgParam)

	if err != nil {
		return err
	}

	//设置状态为可用状态
	var zero int8
	zero = 0
	sysOrg.Status = &zero

	err = fillPids(sysOrg)

	if err != nil {
		return err
	}

	tx := global.GVA_DB.Begin()
	err = SaveOrg(sysOrg, tx)

	if err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}

func fillPids(sysOrg *model.SysOrg) error {

	if sysOrg.Pid != nil && *sysOrg.Pid == 0 {
		sysOrg.Pids = global.LeftSquareBrackets + strconv.Itoa(0) + global.RightSquareBrackets + global.COMMA
	} else {

		//获取父组织机构
		err, pSysOrg := QuerySysOrgById(*sysOrg.Pid)

		if err != nil {
			return err
		}

		sysOrg.Pids = pSysOrg.Pids + global.LeftSquareBrackets + strconv.Itoa(pSysOrg.Id) + global.RightSquareBrackets + global.COMMA
	}

	return nil
}

//校验参数，检查是否存在相同的名称和编码
func checkParamByOrg(sysOrgParam *request.SysOrgParam, isExcludeSelf bool) error {

	id := sysOrgParam.Id

	name := sysOrgParam.Name
	code := sysOrgParam.Code
	pid := sysOrgParam.Pid

	//如果父id不是根节点
	if pid != nil && *pid != 0 {
		err, pOrg := QuerySysOrgById(*pid)
		if err != nil {
			return err
		}

		if pOrg.Id == 0 {
			//父机构不存在
			return errors.New("组织机构不存在")
		}
	}

	// 如果是编辑，父id和自己的id不能一致
	if isExcludeSelf {
		if sysOrgParam.Id == *sysOrgParam.Pid {
			return errors.New("父节点不能和本节点一致，请从新选择父节点")
		}
	}

	var sysOrgSlice *model.SysOrg

	db := global.GVA_DB

	dbName := db.Where("name = ?", name).Where("status <> ?", 2)
	dbCode := db.Where("code = ?", code).Where("status <> ?", 2)

	if isExcludeSelf {
		dbName = dbName.Where("id <> ?", id)
		dbCode = dbCode.Where("id <> ?", id)
	}

	var countByName int64
	err := dbName.Find(&sysOrgSlice).Count(&countByName).Error

	if err != nil {
		return err
	}

	var countByCode int64
	err = dbCode.Find(&sysOrgSlice).Count(&countByCode).Error

	if err != nil {
		return err
	}

	if countByName >= 1 {
		return errors.New("组织机构名称重复，请检查name参数")
	}

	if countByCode >= 1 {
		return errors.New("组织机构编码重复，请检查code参数")
	}

	return nil
}

func OrgEdit(sysOrgParam *request.SysOrgParam, c *gin.Context) error {

	err, sysOrg := QuerySysOrgById(sysOrgParam.Id)

	if err != nil {
		return err
	}

	if sysOrg.Id == 0 {
		return errors.New("组织机构不存在")
	}

	id := sysOrg.Id

	err, superAdmin := IsSuperAdmin(c)

	if err != nil {
		return err
	}

	if !superAdmin {

		dataScopes := sysOrgParam.DataScope

		isContain, _ := utils.Contain(id, dataScopes)

		//数据范围为空
		if len(dataScopes) < 0 {
			return errors.New("没有权限操作该数据，请联系管理员")
		} else if !isContain {
			//所添加的组织机构的父机构不在自己的数据范围内
			return errors.New("没有权限操作该数据，请联系管理员")
		}
	}

	err = checkParamByOrg(sysOrgParam, true)

	if err != nil {
		return err
	}

	tx := global.GVA_DB.Begin()

	//如果名称有变化，则修改对应员工的机构相关信息
	if sysOrg.Name != sysOrgParam.Name {
		err = updateEmpOrgInfo(sysOrg.Id, sysOrg.Name, tx)

		if err != nil {
			tx.Rollback()
			return err
		}
	}

	err = utils.SimpleCopyProperties(&sysOrg, sysOrgParam)

	if err != nil {
		tx.Rollback()
		return err
	}

	err = fillPids(&sysOrg)

	if err != nil {
		tx.Rollback()
		return err
	}

	//不能修改状态，用修改状态接口修改状态
	sysOrg.Status = nil

	err = UpdateSysOrg(sysOrg, tx)

	if err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}

func OrgDelete(sysOrgParam *request.SysOrgParam, c *gin.Context) error {

	err, sysOrg := QuerySysOrgById(sysOrgParam.Id)

	if err != nil {
		return err
	}

	if sysOrg.Id == 0 {
		return errors.New("组织机构不存在")
	}

	id := sysOrg.Id

	err, superAdmin := IsSuperAdmin(c)

	if err != nil {
		return err
	}

	if !superAdmin {

		dataScopes := sysOrgParam.DataScope

		isContain, _ := utils.Contain(id, dataScopes)

		//数据范围为空
		if len(dataScopes) < 0 {
			return errors.New("没有权限操作该数据，请联系管理员")
		} else if !isContain {
			//所操作的数据不在自己的数据范围内
			return errors.New("没有权限操作该数据，请联系管理员")
		}
	}

	// 该机构下有员工，则不能删
	err, hasOrgEmp := HasOrgEmp(id)
	if hasOrgEmp {
		return errors.New("该机构下有员工，无法删除")
	}

	// 该附属机构下若有员工，则不能删除
	err, hasExtOrgEmp := HasExtOrgEmp(id)

	if hasExtOrgEmp {
		return errors.New("该机构下有员工，无法删除")
	}

	// 级联删除子节点
	err, childIdSlice := GetChildIdListById(id)

	childIdSlice = append(childIdSlice, id)

	tx := global.GVA_DB.Begin()

	err = tx.Model(model.SysOrg{}).Where("id in (?)", childIdSlice).Update("status", 2).Error

	if err != nil {
		tx.Rollback()
		return err
	}

	// 级联删除该机构及子机构对应的角色-数据范围关联信息
	err = DeleteRoleDataScopeListByOrgIdList(childIdSlice, tx)

	if err != nil {
		tx.Rollback()
		return err
	}

	// 级联删除该机构子机构对应的用户-数据范围关联信息
	err = DeleteUserDataScopeListByOrgIdList(childIdSlice, tx)

	if err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}
